package Engine.Character;

import Engine.Game.GameAdmin;
import Main.Tuxedo;
import java.io.IOException;
import javax.microedition.lcdui.Image;

/**
 * Model for characters in the overworld. It defines the sequences of movement.
 * @author Gerardo Galíndez
 */
public class OverworldCharacter extends Character {

    //---------------------------------------------------------
    //Object administrator-------------------------------------
    private GameAdmin currentAdmin;
    //Movement sequences---------------------------------------
    private int[] standSequence = {0, 1, 2, 1};
    private int[] runningUpSequence = {3, 4, 5, 4};
    private int[] runningDownSequence = {6, 7, 8, 7};
    private int[] runningRightSequence = {9, 10, 11, 10};
    private int[] runningLeftSequence = {12, 13, 14, 13};
    private int[] currentSequence = {};
    //Counter of the frames for movement-----------------------
    private int movementCounter;
    //Maximum number of frames per sequence--------------------
    private final int FRAME_LIMITER = 3;
    private final int characterCode;
    private int XP;
    private char difficulty;
    private int nextLevelPoints;
    //---------------------------------------------------------
    /**
     * Integer index code representing lyn character
     */
    public static final int LYN = 0;
    /**
     * Integer index code representing eliwood character
     */
    public static final int ELIWOOD = 1;
    /**
     * Integer index code representing eirik character
     */
    public static final int EIRIK = 2;

    /**
     * Creates the correct sprite according to the character code
     * @param characterCode
     * @param admin
     */
    public OverworldCharacter(int characterCode, GameAdmin admin, char difficulty) {
        super(getImage(characterCode), getFrameWidth(characterCode), getFrameHeight(characterCode), getElement(characterCode));
        this.characterCode = characterCode;
        this.currentAdmin = admin;
        this.movementCounter = 0;
        this.setFrameSequence(this.standSequence);
        this.difficulty = difficulty;
        this.nextLevelPoints = this.inicializeNextLevelPoints();
        this.XP = 0;
        super.setMaxHealthPoints(400);
        super.setCurrentHealthPoints(super.getMaxHealthPoints());
        super.setMaxMagicPoints(250);
        super.setCurrentMagicPoints(super.getMaxMagicPoints());
    }

    //Inicializes the next level points for the second level
    private int inicializeNextLevelPoints() {
        switch (this.difficulty) {
            case Tuxedo.EASY:
                return 4;
            case Tuxedo.MEDIUM:
                return 8;
            case Tuxedo.HARD:
                return 15;
            default:
                return -1;
        }
    }

    //Gets the right image for each character
    private static Image getImage(int characterCode) {
        try {
            switch (characterCode) {
                case LYN:
                    return Image.createImage("/Images/Players/Lyn-Overworld.png");
                case ELIWOOD:
                    return Image.createImage("/Images/Players/Eliwood-Overworld.png");
                case EIRIK:
                    return Image.createImage("/Images/Players/Eirik-Overworld.png");
                default:
                    System.out.println("Incorrect character code.");
                    return null;
            }
        } catch (IOException ioex) {
            ioex.printStackTrace();
            return null;
        }
    }

    //Gets the width of each character
    private static int getFrameWidth(int characterCode) {
        switch (characterCode) {
            case LYN:
                return 19;
            case ELIWOOD:
                return 25;
            case EIRIK:
                return 19;
            default:
                return -1;
        }
    }

    //Gets the height of each character
    private static int getFrameHeight(int characterCode) {
        switch (characterCode) {
            case LYN:
                return 18;
            case ELIWOOD:
                return 20;
            case EIRIK:
                return 17;
            default:
                return -1;
        }
    }

    //Gets the element of each character
    private static int getElement(int characterCode) {
        switch (characterCode) {
            case LYN:
                return Character.WIND;
            case ELIWOOD:
                return Character.FIRE;
            case EIRIK:
                return Character.WATER;
            default:
                return -1;
        }
    }

    /**
     * Changes the sequence to running up and then moves the sprite in the negative y-axis
     */
    public void moveUp() {
        if (currentSequence != this.runningUpSequence) {
            this.setFrameSequence(this.runningUpSequence);
            currentSequence = this.runningUpSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            currentAdmin.step();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
        super.move(0, -3);
    }

    /**
     * Changes the sequence to running down and then moves the sprite in the positive y-axis
     */
    public void moveDown() {
        if (currentSequence != this.runningDownSequence) {
            this.setFrameSequence(this.runningDownSequence);
            currentSequence = this.runningDownSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            currentAdmin.step();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
        super.move(0, 3);
    }

    /**
     * Changes the sequence to running left and then moves the sprite in the negative x-axis
     */
    public void moveLeft() {

        if (currentSequence != this.runningLeftSequence) {
            this.setFrameSequence(this.runningLeftSequence);
            currentSequence = this.runningLeftSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            currentAdmin.step();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
        super.move(-3, 0);
    }

    /**
     * Changes the sequence to running right and then moves the sprite in the positive x-axis
     */
    public void moveRight() {
        if (currentSequence != this.runningRightSequence) {
            this.setFrameSequence(this.runningRightSequence);
            currentSequence = this.runningRightSequence;
        }
        if (movementCounter > FRAME_LIMITER) {
            super.nextFrame();
            currentAdmin.step();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
        super.move(3, 0);
    }

    /**
     * Changes the sequence to stand
     */
    public void stand() {
        if (currentSequence != this.standSequence) {
            this.setFrameSequence(this.standSequence);
            currentSequence = this.standSequence;
        }
        if (movementCounter > FRAME_LIMITER + 15) {
            super.nextFrame();
            movementCounter = 0;
        } else {
            movementCounter++;
        }
    }

    /**
     * Gets the character code
     * @return the character code
     */
    public int getCharacterCode() {
        return characterCode;
    }

    /**
     * Gets the current experience points of the character
     * @return the current experience points
     */
    public int getCurrentXP() {
        return this.XP;
    }

    /**
     * Adds the experience points gain and calculate if need to level up
     * @param experienceDifferential the amount of experience points gained
     */
    public void addExperiencePoints(int experienceDifferential) {
        this.XP += experienceDifferential;
        if (this.XP >= this.getNextLevelPoints()) {
            super.setCurrentLevel(1);
            this.setNextLevelPoints();
        }
    }

    /**
     * Switches between the difficulty and then calculate the next level points according to a formula
     */
    public void setNextLevelPoints() {
        switch (this.difficulty) {
            case Tuxedo.EASY:
                if (this.getCurrentLevel() <= 6) {
                    this.nextLevelPoints = (this.getCurrentLevel() + 1) * (this.getCurrentLevel() + 1);
                } else {
                    this.nextLevelPoints += this.getCurrentLevel() + 11;
                }
                break;
            case Tuxedo.MEDIUM:
                if (this.getCurrentLevel() <= 6) {
                    this.nextLevelPoints = (3 * (this.getCurrentLevel() + 1)) * (this.getCurrentLevel() + 1) + 10;
                } else {
                    this.nextLevelPoints += this.getCurrentLevel() + 11;
                }
                break;
            case Tuxedo.HARD:
                if (this.getCurrentLevel() <= 6) {
                    this.nextLevelPoints = (3 * (this.getCurrentLevel() + 1)) * (2 * (this.getCurrentLevel() + 1)) + 10;
                } else {
                    this.nextLevelPoints += this.getCurrentLevel() + 11;
                }
                break;

        }
    }

    /**
     * Return the next level points
     * @return the next level points
     */
    public int getNextLevelPoints() {
        return nextLevelPoints;
    }
}